<html><head><title>Chapter 5: Container - Pipelining Tasks</title></head><body><div id='tit'>Chapter 5: Container - Pipelining Tasks</div><div id='cate'>源码品读</div><div id='date'>2010年07月20日 星期二 01:56 P.M.</div><div id='page'>12</div><a id='url' href='http://hi.baidu.com/hxzon/blog/item/4c3ea2c217d673160ff477e4.html'>http://hi.baidu.com/hxzon/blog/item/4c3ea2c217d673160ff477e4.html</a><div id='cnt'><div> 
 <p>Chapter 5: Container - Pipelining Tasks</p> 
 <p>《How Tomcat Works》pdf hxzon<br /> tomcat源码品读</p> 
 <p>=========================================</p> 
 <h1>Chapter 5: Container</h1> 
 <p>A container is a module that processes the requests for a servlet and populates the <br /> response objects for web clients. A container is represented by the <br /> org.apache.catalina.Container interface and there are four types of containers: <br /> Engine, Host, Context, and Wrapper. This chapter covers Context and Wrapper and <br /> leaves Engine and Host to Chapter 13. This chapter starts with the discussion of the <br /> Container interface, followed by the pipelining mechanism in a container. It then <br /> looks at the Wrapper and Context interfaces. Two applications conclude this chapter <br /> by presenting a simple wrapper and a simple context respectively.</p> 
 <h2>The Container Interface</h2> 
 <p>A container must implement org.apache.catalina.Container. As you have seen in <br /> Chapter 4, you pass an instance of Container to the setContainer method of the <br /> connector, so that the connector can call the container's invoke method. Recall the <br /> following code from the Bootstrap class in the application in Chapter 4.</p> 
 <pre>HttpConnector connector = new HttpConnector(); <br />    SimpleContainer container = new SimpleContainer(); <br />    connector.setContainer(container);</pre> 
 <p>The first thing to note about containers in Catalina is that there are four types of <br /> containers at different conceptual levels:</p> 
 <ul> 
  <li>Engine. Represents the entire Catalina servlet engine.</li> 
  <li>Host. Represents a virtual host with a number of contexts.</li> 
  <li>Context. Represents a web application. A context contains one or more wrappers.</li> 
  <li>Wrapper. Represents an individual servlet.</li> 
 </ul> 
 <p>Each conceptual level above is represented by an interface in the org.apache.catalina <br /> package. These interfaces are Engine, Host, Context, and Wrapper. All the four <br /> extends the Container interface. Standard implementations of the four containers are <br /> StandardEngine, StandardHost, StandardContext, and StandardWrapper, <br /> respectively, all of which are part of the org.apache.catalina.core package.</p> 
 <p>Figure 5.1 shows the class diagram of the Container interface and its sub-interfaces <br /> and implementations. Note that all interfaces are part of the org.apache.catalina <br /> package and all classes are part of the org.apache.catalina.core package.</p> 
 <p><span><img class="blogimg" border="0" small="0" src="image/Chapter 5- Container.7d575466b29dbd64aa184c12.jpg" /><p class="origImg">http://hiphotos.baidu.com/hxzon/pic/item/7d575466b29dbd64aa184c12.jpg</p><br /> </span></p> 
 <p>Figure 5.1: The class diagram of Container and its related types&nbsp;&nbsp; <br /> Note&nbsp;&nbsp; All implementation classes derive from the abstract class ContainerBase.</p> 
 <p>A functional Catalina deployment does not need all the four types of containers. For <br /> example, the container module in this chapter's first application consists of only a <br /> wrapper. The second application is a container module with a context and a wrapper. <br /> Neither host nor engine is needed in the applications accompanying this chapter.</p> 
 <p>A container can have zero or more child containers of the lower level. For instance, <br /> a context normally has one or more wrappers and a host can have zero or more <br /> contexts. However, a wrapper, being the lowest in the 'hierarchy', cannot contain a <br /> child container. To add a child container to a container, you use the Container <br /> interface's addChild method whose signature is as follows.</p> 
 <pre>public void addChild(Container child);</pre> 
 <p>To remove a child container from a container, call the Container interface's <br /> removeChild method. The remove method's signature is as follows.</p> 
 <pre>public void removeChild(Container child);</pre> 
 <p>In addition, the Container interface supports the finding of a child container or a <br /> collection of all child containers through the findChild and findChildren methods. <br /> The signatures of both methods are the following.</p> 
 <pre>public Container findChild(String name); <br />public Container[] findChildren();</pre> 
 <p>A container can also contain a number of support components such as Loader, <br /> Logger, Manager, Realm, and Resources. We will discuss these components in later <br /> chapters. One thing worth noting here is that the Container interface provides the <br /> get and set methods for associating itself with those components. These methods<br /> include getLoader and setLoader, getLogger and setLogger, getManager and <br /> setManager, getRealm and setRealm, and getResources and setResources.</p> 
 <p>More interestingly, the Container interface has been designed in such a way that at <br /> the time of deployment a Tomcat administrator can determine what a container <br /> performs by editing the configuration file (server.xml). This is achieved by <br /> introducing a pipeline and a set of valves in a container, which we will discuss in the <br /> next section, &quot;Pipelining Tasks&quot;.</p> 
 <p>Note&nbsp;&nbsp; The Container interface in Tomcat 4 is slightly different from that in Tomcat 5. <br /> For example, in Tomcat 4 this interface has a map method, which no longer <br /> exists in the Container interface in Tomcat 5.</p> 
 <h2>Pipelining Tasks</h2> 
 <p>This section explains what happens when a container's invoke method is called by <br /> the connector. This section then discusses in the sub-sections the four related <br /> interfaces in the org.apache.catalina package: Pipeline, Valve, ValveContext, and <br /> Contained.</p> 
 <p>A pipeline contains tasks that the container will invoke. A valve represents a specific <br /> task. There is one basic valve in a container's pipeline, but you can add as many <br /> valves as you want. The number of valves is defined to be the number of additional <br /> valves, i.e. not including the basic valve. Interestingly, valves can be added <br /> dynamically by editing Tomcat's configuration file (server.xml). Figure 5.2 shows a <br /> pipeline and its valves.</p> 
 <p>（hxzon：原电子书缺图）</p> 
 <p>Figure 5.2: Pipeline and valves&nbsp;&nbsp;</p> 
 <p>If you understand servlet filters, it is not hard to imagine how a pipeline and its valve <br /> work. A pipeline is like a filter chain and each valve is a filter. Like a filter, a valve <br /> can manipulate the request and response objects passed to it. After a valve finishes <br /> processing, it calls the next valve in the pipeline. The basic valve is always called the <br /> last.</p> 
 <p>A container can have one pipeline. When a container's invoke method is called, the <br /> container passes processing to its pipeline and the pipeline invokes the first valve in <br /> it, which will then invoke the next valve, and so on, until there is no more valve in <br /> the pipeline. You might imagine that you could have the following pseudo code inside <br /> the pipeline's invoke method:</p> 
 <pre>// invoke each valve added to the pipeline for (int n=0; n&lt;valves.length; n++) { <br />   valve[n].invoke( ... ); <br />} <br />// then, invoke the basic valve <br />basicValve.invoke( ... );</pre> 
 <p>However, the Tomcat designer chose a different approach by introducing the <br /> org.apache.catalina.ValveContext interface. Here is how it works.</p> 
 <p>A container does not hard code what it is supposed to do when its invoke method is <br /> called by the connector. Instead, the container calls its pipeline's invoke method. <br /> The Pipeline interface's invoke method has the following signature, which is exactly <br /> the same as the invoke method of the Container interface.</p> 
 <pre>public void invoke(Request request, Response response) <br />   throws IOException, ServletException;</pre> 
 <p>Here is the implementation of the Container interface's invoke method in the <br /> org.apache.catalina.core.ContainerBase class.</p> 
 <pre>public void invoke(Request request, Response response) <br />   throws IOException, ServletException { <br />   pipeline.invoke(request, response); <br />}</pre> 
 <p>where pipeline is an instance of the Pipeline interface inside the container.</p> 
 <p>Now, the pipeline has to make sure that all the valves added to it as well as its basic <br /> valve must be invoked once. The pipeline does this by creating an instance of the <br /> ValveContext interface. The ValveContext is implemented as an inner class of the <br /> pipeline so that the ValveContext has access to all members of the pipeline. The <br /> most important method of the ValveContext interface is invokeNext:</p> 
 <pre>public void invokeNext(Request request, Response response) <br />   throws IOException, ServletException</pre> 
 <p>After creating an instance of ValveContext, the pipeline calls the invokeNext method <br /> of the ValveContext. The ValveContext will first invoke the first valve in the pipeline <br /> and the first valve will invoke the next valve before the first valve does its task. The <br /> ValveContext passes itself to each valve so that the valve can call the invokeNext <br /> method of the ValveContext. Here is the signature of the invoke method of the Valve <br /> interface.</p> 
 <pre>public void invoke(Request request, Response response, <br />   ValveContext ValveContext) throws IOException, ServletException</pre> 
 <p>An implementation of a valve's invoke method will be something like the following.</p> 
 <pre>public void invoke(Request request, Response response, <br />   ValveContext valveContext) throws IOException, ServletException { <br />   // Pass the request and response on to the next valve in our pipeline <br />   valveContext.invokeNext(request, response); <br />   // now perform what this valve is supposed to do <br />     ... <br />}</pre> 
 <p>The org.apache.catalina.core.StandardPipeline class is the implementation of <br /> Pipeline in all containers. In Tomcat 4, this class has an inner class called <br /> StandardPipelineValveContext that implements the ValveContext interface. Listing <br /> 5.1 presents the StandardPipelineValveContext class.</p> 
 <p>Listing 5.1: The StandardPipelineValveContext class in Tomcat 4</p> 
 <pre>protected class StandardPipelineValveContext implements ValveContext { <br />   protected int stage = 0; <br />   public String getInfo() { <br />     return info; <br />   } <br />   public void invokeNext(Request request, Response response) <br />     throws IOException, ServletException { <br /> <br />     int subscript = stage; <br />     stage = stage + 1; <br /> <br />     // Invoke the requested Valve for the current request thread <br />     if (subscript &lt; valves.length) { <br />       valves[subscript].invoke(request, response, this); <br />     } <br />     else if ((subscript == valves.length) &amp;&amp; (basic != null)) { <br />       basic.invoke(request, response, this); <br />     } <br />     else { <br />       throw new ServletException <br />         (sm.getString(&quot;standardPipeline.noValve&quot;)); <br />     } <br />   } <br />}</pre> 
 <p>The invokeNext method uses subscript and stage to remember which valve is being <br /> invoked. When first invoked from the pipeline's invoke method, the value of <br /> subscript is 0 and the value of stage is 1. Therefore, the first valve (array index 0) is <br /> invoked. The first valve in the pipeline receives the ValveContext instance and <br /> invokes its invokeNext method. This time, the value of subscript is 1 so that the <br /> second valve is invoked, and so on.</p> 
 <p>When the invokeNext method is called from the last valve, the value of subscript is <br /> equal to the number of valves. As a result, the basic valve is invoked.</p> 
 <p>Tomcat 5 removes the StandardPipelineValveContext class from StandardPipeline <br /> and instead relies on the org.apache.catalina.core.StandardValveContext class, <br /> which is presented in Listing 5.2.</p> 
 <p>Listing 5.2: The StandardValveContext class in Tomcat 5&nbsp;&nbsp;</p> 
 <pre>package org.apache.catalina.core; <br /> <br />import java.io.IOException; <br />import javax.servlet.ServletException; <br />import org.apache.catalina.Request; <br />import org.apache.catalina.Response; <br />import org.apache.catalina.Valve; <br />import org.apache.catalina.ValveContext; <br />import org.apache.catalina.util.StringManager; <br /> <br />public final class StandardValveContext implements ValveContext { <br />   protected static StringManager sm = <br />     StringManager.getManager(Constants.Package); <br />   protected String info = <br />     &quot;org.apache.catalina.core.StandardValveContext/1.0&quot;; <br />   protected int stage = 0; <br />   protected Valve basic = null; <br />   protected Valve valves[] = null; <br />   public String getInfo() { <br />     return info; <br /> <br />   } <br /> <br />   public final void invokeNext(Request request, Response response) <br />     throws IOException, ServletException { <br />     int subscript = stage; <br />     stage = stage + 1; <br />     // Invoke the requested Valve for the current request thread <br />     if (subscript &lt; valves.length) {        valves[subscript].invoke(request, response, this); <br />     } <br />     else if ((subscript == valves.length) &amp;&amp; (basic != null)) { <br />       basic.invoke(request, response, this); <br />     } <br />     else { <br />       throw new ServletException <br />         (sm.getString(&quot;standardPipeline.noValve&quot;)); <br />     } <br />   } <br /> <br />   void set(Valve basic, Valve valves[]) { <br />     stage = 0; <br />     this.basic = basic; <br />     this.valves = valves; <br />   } <br />}</pre> 
 <p>Can you see the similarities between the StandardPipelineValveContext class in <br /> Tomcat 4 and the StandardValveContext class in Tomcat 5? <br /> We will now explain the Pipeline, Valve, and ValveContext interfaces in more detail. <br /> Also discussed is the org.apache.catalina.Contained interface that a valve class <br /> normally implements.</p> 
 <h3>The Pipeline Interface</h3> 
 <p>The first method of the Pipeline interface that we mentioned was the invoke method, <br /> which a container calls to start invoking the valves in the pipeline and the basic valve. <br /> The Pipeline interface allows you to add a new valve through its addValve method <br /> and remove a valve by calling its removeValve method. Finally, you use its setBasic <br /> method to assign a basic valve to a pipeline and its getBasic method to obtain the <br /> basic valve. The basic valve, which is invoked last, is responsible for processing the <br /> request and the corresponding response. The Pipeline interface is given in Listing <br /> 5.3.</p> 
 <p>Listing 5.3: The Pipeline interface&nbsp;&nbsp;</p> 
 <pre>package org.apache.catalina; <br />import java.io.IOException; <br /> <br />import javax.servlet.ServletException;  <br />public interface Pipeline { <br />   public Valve getBasic(); <br />   public void setBasic(Valve valve); <br />   public void addValve(Valve valve); <br />   public Valve[] getValves(); <br />   public void invoke(Request request, Response response) <br />     throws IOException, ServletException; <br />   public void removeValve(Valve valve); <br />}</pre> 
 <h3>The Valve Interface</h3> 
 <p>The Valve interface represents a valve, the component responsible for processing a <br /> request. This interface has two methods: invoke and getInfo. The invoke method has <br /> been discussed above. The getInfo method returns information about the valve <br /> implementation. The Valve interface is given in Listing 5.4.</p> 
 <p>Listing 5.4: The Valve interface</p> 
 <pre>package org.apache.catalina; <br />import java.io.IOException; <br />import javax.servlet.ServletException; <br /> <br />public interface Valve { <br />   public String getInfo(); <br />   public void invoke(Request request, Response response, <br />     ValveContext context) throws IOException, ServletException; <br />}</pre> 
 <h3>The ValveContext Interface</h3> 
 <p>This interface has two methods: the invokeNext method, which has been discussed <br /> above, and the getInfo method, which returns information about the ValveContext <br /> implementation. The ValveContext interface is given in Listing 5.5.</p> 
 <p>Listing 5.5: The ValveContext interface&nbsp;&nbsp;</p> 
 <pre>package org.apache.catalina; import java.io.IOException; <br />import javax.servlet.ServletException; <br /> <br />public interface ValveContext { <br />   public String getInfo(); <br />   public void invokeNext(Request request, Response response) <br />     throws IOException, ServletException; <br /> <br />}</pre> 
 <h3>The Contained Interface</h3> 
 <p>A valve class can optionally implement the org.apache.catalina.Contained interface. <br /> This interface specifies that the implementing class is associated with at most one <br /> container instance. The Contained interface is given in Listing 5.6.</p> 
 <p>Listing 5.6: The Contained interface&nbsp;&nbsp;</p> 
 <pre>package org.apache.catalina; <br />public interface Contained { <br />   public Container getContainer(); <br />   public void setContainer(Container container);</pre> 
 <h2>The Wrapper Interface</h2> 
 <p>The org.apache.catalina.Wrapper interface represents a wrapper. A wrapper is a <br /> container representing an individual servlet definition. The Wrapper interface <br /> extends Container and adds a number of methods. Implementations of Wrapper are <br /> responsible for managing the servlet life cycle for their underlying servlet class, i.e. <br /> calling the init, service, and destroy methods of the servlet. Since a wrapper is the <br /> lowest level of container, you must not add a child to it. A wrapper throws an <br /> IllegalArgumantException if its addChild method is called.</p> 
 <p>Important methods in the Wrapper interface include allocate and load. The allocate <br /> method allocates an initialed instance of the servlet the wrapper represents. The <br /> allocate method must also take into account whether or not the servlet implements <br /> the javax.servlet.SingleThreadModel interface, but we will discuss this later in <br /> Chapter 11. The load method loads and initializes an instance of the servlet the <br /> wrapper represents. The signatures of the allocate and load methods are as follows.</p> 
 <pre>public javax.servlet.Servlet allocate() throws javax.servlet.ServletException; <br />public void load() throws javax.servlet.ServletException;</pre> 
 <p>The other methods will be covered in Chapter 11 when we discuss the <br /> org.apache.catalina.core.StandardWrapper class.</p> 
 <h2>The Context Interface</h2> 
 <p>A context is a container that represents a web application. A context usually has one <br /> or more wrappers as its child containers. <br /> Important methods include addWrapper, createWrapper, etc. This interface will be <br /> covered in more detail in Chapter 12.</p> 
 <p> </p> 
 <p> </p> 
 <p> </p> 
 <p> </p> 
 <p> </p> 
 <p> </p> 
 <p> </p> 
 <p> </p> 
 <p> </p> 
 <p> </p> 
 <p> </p> 
 <p> </p> 
 <p> </p> 
 <p> </p> 
 <p> </p> 
</div></div></body></html>